////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2016-2018 Qualcomm Technologies, Inc.
// All Rights Reserved.
// Confidential and Proprietary - Qualcomm Technologies, Inc.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @file  camxcmdbuffermanager.h
/// @brief CmdBufferManager class declaration
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#ifndef CAMXCMDBUFFERMANAGER_H
#define CAMXCMDBUFFERMANAGER_H

#include "camxcmdbuffer.h"
#include "camxdefs.h"
#include "camxhal3defs.h"
#include "camxlist.h"
#include "camxpacket.h"
#include "camxpacketresource.h"
#include "camxtypes.h"

CAMX_NAMESPACE_BEGIN

class CmdBuffer;

/// @brief Parameters that describe resources in a pool (size, number)
///        This will be mainly size and number of resources, but also type-specific parameters for initialization.
struct ResourceParams
{
    UINT                        resourceSize;   ///< Size of resource
    UINT                        poolSize;       ///< Pool size
    UINT32                      alignment;      ///< Required alignment
    PacketResourceUsageFlags    usageFlags;     ///< Flags that describe the resource
    UINT32                      memFlags;       ///< Resource memory flags
    const INT32*                pDeviceIndices; ///< Pointer to indices of devices accessing this resource
    UINT32                      numDevices;     ///< Number of indices pointed to by pDeviceIndices
    union
    {
        PacketParams            packetParams;   ///< Packet parameters
        CmdParams               cmdParams;      ///< Command parameters
    };
};

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @brief Class that implements CAMX packet memory manager.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class CmdBufferManager
{
public:

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// Create
    ///
    /// @brief  Create and initialize CmdBufferManager instance
    ///
    /// @param  pParams             Parameters to pass the created manager
    /// @param  ppCmdBufferManager  Pointer to the manager to fill
    ///
    /// @return CamxResult
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    static CamxResult Create(
        const ResourceParams* pParams,
        CmdBufferManager**    ppCmdBufferManager);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// CmdBufferManager
    ///
    /// @brief  Constructor
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CmdBufferManager();

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// ~CmdBufferManager
    ///
    /// @brief  Destructor
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    virtual ~CmdBufferManager();

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// Initialize
    ///
    /// @brief  Allocate memory and setup the pools. It will first free all previously-allocated resources.
    ///
    /// @param  pParams         Array of resource parameters, sorted based on size, in increasing order
    ///
    /// @return CamxResult
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CamxResult Initialize(
        const ResourceParams*   pParams);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// Uninitialize
    ///
    /// @brief  Uninitialize the resource manager
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID Uninitialize();

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// Recycle
    ///
    /// @brief  Recycle the buffer. This should be called to recycle resources manually i.e. independent of requests. It is
    ///         assumed the pResource passed in here was obtained by the client using the GetBuffer(..) interface and not
    ///         GetBufferForRequest(..)
    ///
    /// @param  pResource Resource to recycle
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID Recycle(
        PacketResource* pResource);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// RecycleAll
    ///
    /// @brief  Recycle all the buffers of the given request
    ///
    /// @param  requestId The requestId of the retired request.
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID RecycleAll(
        UINT64 requestId);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetBufferForRequest
    ///
    /// @brief  This function gets a buffer from the free pool. It removes the buffer from the free pool and also inserts it
    ///         into the busy pool. If the client uses this interface to get a buffer it is assumed the client will not
    ///         manually recycle this buffer i.e. this class will automatically recycle the buffer once the requestId retires
    ///
    /// @param  requestId The request Id to which this resource's lifecycle will be tied to
    /// @param  ppBuffer  Address of a pointer that will be filled to point to a free buffer
    ///
    /// @return CamxResult
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CamxResult GetBufferForRequest(
        UINT64           requestId,
        PacketResource** ppBuffer);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetBuffer
    ///
    /// @brief  This function removes the buffer from the free pool but does not insert it into the busy pool. If the client
    ///         invokes this function to get a buffer it is assumed the client will manually recycle this buffer by calling
    ///         the Recycle() interface
    ///
    /// @param  ppBuffer  Address of a pointer that will be filled to point to a free buffer
    ///
    /// @return CamxResult
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CamxResult GetBuffer(
        PacketResource** ppBuffer);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// CheckBufferWithRequest
    ///
    /// @brief  This function checks a buffer from the busy pool with request id.
    ///
    /// @param  requestId The request Id to which this resource's lifecycle will be tied to
    /// @param  ppBuffer  Address of a pointer that will be filled to point to a buffer
    ///
    /// @return CamxResult
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CamxResult CheckBufferWithRequest(
        UINT64           requestId,
        PacketResource** ppBuffer);

protected:
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// InitializePool
    ///
    /// @brief  Helper method that initializes the pool of free buffers
    ///
    /// @return CamxResult
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    virtual CamxResult InitializePool();

private:
    CmdBufferManager(const CmdBufferManager&) = delete;             // Disallow the copy constructor.
    CmdBufferManager& operator=(const CmdBufferManager&) = delete;  // Disallow assignment operator.

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// FreeMemHandles
    ///
    /// @brief  Free CSL memory handles
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID FreeMemHandles();

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// FreeResources
    ///
    /// @brief  Free all resources (CSL memory and packet resource objects).
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID FreeResources();

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetPaddedSize
    ///
    /// @brief  Get the size that accounts for alignment and padding
    ///
    /// @param  sizeInBytes         Size to be padded
    /// @param  alignmentInBytes    The desired alignment
    ///
    /// @return Padded size
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    UINT32 GetPaddedSize(
        UINT32 sizeInBytes,
        UINT32 alignmentInBytes);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// UninitializePools
    ///
    /// @brief  Helper method that uninitializes one single pool of resources
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID UninitializePools();

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// CreateResource
    ///
    /// @brief  Resource factory method
    ///
    /// @param  pBufferInfo CSL allocation to break up
    /// @param  offset      Offset from the allocation where the resource memory begins
    /// @param  pParams     Object-specific parameters
    /// @param  ppResource  Address of the result resource pointer
    ///
    /// @return CamxResult
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CamxResult CreateResource(
        CSLBufferInfo*      pBufferInfo,
        UINT32              offset,
        ResourceParams*     pParams,
        PacketResource**    ppResource);

    BOOL                        m_initialized;    ///< initialized
    LightweightDoublyLinkedList m_CSLAllocations; ///< list of CSLMemHandle (CSL allocations)
    ResourceParams              m_params;         ///< Parameters of this pool
    UINT                        m_numResources;   ///< Number of resources based on the provided parameters
    LightweightDoublyLinkedList m_freePool;      ///< Pool of free buffers
    LightweightDoublyLinkedList m_busyPool;      ///< Pool of busy buffers
    Mutex*                      m_pLock;          ///< Mutex to protect buffer manager internal state
};

CAMX_NAMESPACE_END

#endif // CAMXCMDBUFFERMANAGER_H
